﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.SceneManagement;
using RainEngine.Effects;
using Microsoft.Xna.Framework.Content;

namespace RainEngine.SceneNodes
{
    /// <summary>
    /// 使用Microsoft.Xna.Framework.Graphics.Model定义的几何模型。
    /// </summary>
    public class ModelSceneNode : Renderable3DSceneNode,ISceneNodeLighting,ISceneNodeFog 
    {
        #region 成员变量和构造函数

        /// <summary>
        /// 模型
        /// </summary>
        protected Model model;

        /// <summary>
        /// 模型使用的图元数量
        /// </summary>
        int primitives;

        /// <summary>
        /// 模型名称，包含路径
        /// </summary>
        string modelAssetName;

        /// <summary>
        /// 各部件转换矩阵数组
        /// </summary>
        public Matrix[] modelTransforms;

        /// <summary>
        /// 模型的全局包围球
        /// </summary>
        protected BoundingSphere originalSphere;

        /// <summary>
        /// GenericEffect数组，用于保存模型中每个ModelMeshPart的材质
        /// </summary>
        GenericEffect[] effectWrappers;        

        /// <summary>
        /// 模型每秒移动速度
        /// </summary>
        protected float movementSpeed = 60.0f;

        /// <summary>
        /// 模型每秒旋转速度
        /// </summary>
        protected float rotationSpeed = 60.0f;

        /// <summary>
        /// 创建一个ModelSceneNode对象。
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="modelAssetName">模型名称</param>
        public ModelSceneNode(GraphicsDevice graphicsDevice, ContentManager setContent, Scene setScene, string modelAssetName)
            : base(graphicsDevice, setContent,setScene)
        {
            this.modelAssetName = modelAssetName;            
        }

        #endregion

        #region 属性

        /// <summary>
        /// 获取GenericEffect数组
        /// </summary>
        public GenericEffect[] EffectWrappers
        {
            get { return effectWrappers; }
        }

        /// <summary>
        /// 获取或设置模型移动速度
        /// </summary>
        public float MovementSpeed { get; set;}

        /// <summary>
        /// 获取或设置模型旋转速度
        /// </summary>
        public float RotationSpeed{ get; set;}

        /// <summary>
        /// 获取模型。
        /// </summary>
        public Model Model { get { return this.model; } }        

        #endregion

        /// <summary>
        /// 加载模型
        /// </summary>
        internal override void LoadContent()
        {
            model = content.Load<Model>(modelAssetName);
            modelTransforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(modelTransforms);
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public override void Initialize()
        {
            base.Initialize();
            this.UpdateOrder = SceneManagement.SceneNodeOrdering.SceneNode.GetValue();

            // 创建一个材质数组保存所有ModelMeshPart的材质
            List<GenericEffect> effectList = new List<GenericEffect>();            

            // 遍历模型的所有ModelMesh
            foreach (ModelMesh mesh in model.Meshes)
            {
                //根据每个ModelMesh的包围球计算模型的全局包围球
                BoundingSphere meshSphere=new BoundingSphere(Vector3.Zero, 0);;
                mesh.BoundingSphere.Transform(ref modelTransforms[mesh.ParentBone.Index], out meshSphere);
                BoundingSphere.CreateMerged(ref originalSphere, ref meshSphere, out originalSphere);

                // 遍历当前ModelMesh的所有ModelMeshPart
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    // 获取模型使用的图元数量
                    primitives += meshPart.PrimitiveCount;
                    
                    BasicEffect be = meshPart.Effect as BasicEffect;
                    if(be != null)
                    {
                        GenericEffect effectWrapper = new GenericEffect();
                        effectWrapper.TextureEnabled = be.TextureEnabled;
                        effectWrapper.DiffuseTexture  =be.Texture;
                        effectWrapper.PreferPerPixelLighting = be.PreferPerPixelLighting ;
                        effectWrapper.LightingEnabled = be.LightingEnabled;
                        effectWrapper.AmbientLightColor = be.AmbientLightColor;
                        effectWrapper.DiffuseColor =be.DiffuseColor;
                        effectWrapper.SpecularColor = be.SpecularColor;
                        effectWrapper.SpecularPower = be.SpecularPower;
                        effectWrapper.EmissiveColor = be.EmissiveColor;
                        effectWrapper.Alpha = be.Alpha;                        
                        effectWrapper.Light0 = Scene.lights[0];
                        effectWrapper.Light1 = Scene.lights[1];
                        effectWrapper.Light2 = Scene.lights[2];
                        effectWrapper.FogColor = Scene.FogColor;
                        effectWrapper.FogStart = Scene.FogStart;
                        effectWrapper.FogEnd = Scene.FogEnd;
                        effectList.Add(effectWrapper);
                    }
                }
            }
            effectWrappers = effectList.ToArray();
            this.Pose.LocalSize = originalSphere.Radius * 2;
        }        

        /// <summary>
        /// 绘制模型。
        /// </summary>
        /// <param name="gameTime"></param>        
        public override int Draw(GameTime gameTime, Matrix ViewMatrix, Matrix ProjectionMatrix, Vector3 CameraPosition)
        {
            model.CopyAbsoluteBoneTransformsTo(modelTransforms);  

            int effectWrapperCounter = 0;

            // 遍历模型的所有ModelMesh
            for (int mCounter = 0; mCounter < model.Meshes.Count; mCounter++)
            {
                ModelMesh mesh = model.Meshes[mCounter];

                Matrix world = modelTransforms[mesh.ParentBone.Index] * Pose.WorldMatrix;

                int count = mesh.MeshParts.Count;
                // 遍历当前ModelMesh的所有ModelMeshPart
                for (int i = 0; i < count; i++)
                {
                    ModelMeshPart part = mesh.MeshParts[i];

                    effectWrappers[effectWrapperCounter].World = world;
                    effectWrappers[effectWrapperCounter].View = ViewMatrix;
                    effectWrappers[effectWrapperCounter].Projection = ProjectionMatrix;
                    effectWrappers[effectWrapperCounter].EyePosition = CameraPosition;
                    effectWrappers[effectWrapperCounter].OnApply();
                    effectWrappers[effectWrapperCounter].effect.CurrentTechnique.Passes[0].Apply();
                    graphicsDevice.Indices = part.IndexBuffer;
                    graphicsDevice.SetVertexBuffer(part.VertexBuffer);
                    graphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, part.VertexOffset, 0, part.NumVertices, part.StartIndex, part.PrimitiveCount);

                    effectWrapperCounter++;
                }   
            }
            return 1;
        }

        /// <summary>
        /// 设置剪裁平面
        /// </summary>
        /// <param name="Plane">剪裁平面</param>
        public override void SetClipPlane(Vector4? Plane)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].ClipPlane = Plane.Value;
        }

        #region ISceneNodeLighting接口实现

        public void SetAmbientLightColor(Vector3 color)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].AmbientLightColor = color;
        }

        public void SetLightEnabled(int lightIndex, bool lightEnabled)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].effect.Parameters["Lights"].Elements[lightIndex].StructureMembers["enabled"].SetValue(lightEnabled); ;
        }            

        public void SetLightType(int lightIndex, float value)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].effect.Parameters["Lights"].Elements[lightIndex].StructureMembers["lightType"].SetValue(value); ;
        }

        public void SetLightVector3(int lightIndex, string parameterName, Vector3 value)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].effect.Parameters["Lights"].Elements[lightIndex].StructureMembers[parameterName].SetValue(value); ;
        }    

        public void SetLightSpotData(int lightIndex, Vector4 setSpotData)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].effect.Parameters["Lights"].Elements[lightIndex].StructureMembers["spotData"].SetValue(setSpotData);
        }

        #endregion

        #region ISceneNodeFog接口实现

        public void SetFogColor(Vector3 fogColor)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].FogColor = fogColor;
        }

        public void SetFogStart(float fogStart)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].FogStart = fogStart;
        }

        public void SetFogEnd(float fogEnd)
        {
            for (int i = 0; i < effectWrappers.Length; i++)
                effectWrappers[i].FogEnd = fogEnd;
        }

        #endregion
    }
    
}
